#pragma once

#include <Windows.h>
#include <WindowsX.h>
#include <Wtsapi32.h>
#include <set>
#include <map>
#include <iostream>
#include <fstream>

#include "resource.h"
#include "CassiopeiaLibrary.h"

using namespace std;

#define KEYDEVICE_SUCCESS			0
#define KEYDEVICE_NOTFOUND			1
#define KEYDEVICE_INVALIDSERIAL		2
#define KEYDEVICE_ALREADYEXISTS		3

class Core
{
public:
	typedef void (*EVENTPROC)(Core*);
	typedef void (*STATECHANGEDPROC)(Core*, bool);
	typedef void (*SIZECHANGEDPROC)(Core*, size_t);

	Core(HINSTANCE);
	~Core();
	bool Activate(bool = false);
	void Deactivate();

	bool IsActive();
	bool IsLocked();

	void SetLockAtUnplug(bool);
	bool GetLockAtUnplug();

	void SetKeyDeviceCollection(map<DWORD, tstring>);
	int RemoveKeyDevice(DWORD);
	int AddKeyDevice(DWORD, tstring);
	void ClearKeyDevices();
	size_t GetKeyDeviceCount();
	map<DWORD, tstring> GetKeyDeviceCollection();

	void ActiveChanged(STATECHANGEDPROC);
	void LockedChanged(STATECHANGEDPROC);
	void LockAtUnplugChanged(STATECHANGEDPROC);
	void KeyDevicesChanged(SIZECHANGEDPROC);
	void UnauthorizedAccess(EVENTPROC);

private:
	Window* hiddenWindow;
	Window* lockWindow;	
	bool active;
	bool locked;
	bool lockAtUnplug;
	map<DWORD, tstring> keyDevices;
	set<TCHAR> keyDeviceVolumeLetters;
	STATECHANGEDPROC activeChangedPtr;
	STATECHANGEDPROC lockedChangedPtr;
	STATECHANGEDPROC lockAtUnplugChangedPtr;
	SIZECHANGEDPROC keyDevicesChangedPtr;
	EVENTPROC unauthorizedAccessPtr;

	void Lock();
	void LockActions();
	void UnauthorizedAccess();
	void Unlock();
	bool IsAnyKeyDevicePluggedIn();
	void RefreshKeyDevicesVolumeLetters();	

	void OnActiveChanged(bool);
	void OnLockedChanged(bool);
	void OnLockAtUnplugChanged(bool);
	void OnKeyDevicesChanged(size_t);
	void OnUnauthorizedAccess();

	static map<HWND, Core*> instances;

	static LRESULT CALLBACK HiddenWindowWndProc(LPVOID, HWND, UINT, WPARAM, LPARAM);
	static LRESULT CALLBACK LockWindowWndProc(LPVOID, HWND, UINT, WPARAM, LPARAM);


	void CaptureImage(HWND);
	void CaptureVideo(HWND);
};

